# -*- coding: utf-8 -*-
"""行程规划"""
import datetime
import json
import uuid
from urlparse import urlparse

from flask import request, g, current_app, jsonify
from werkzeug.utils import MultiDict
from mongoengine import Q

from app.decorators import validate_form
from app.forms import VacationPoiSearchForm, PlanBookForm
from app.data_structures import NoAppVersion
from app.models import (
    Locality, Destination, DestinationOption,
    DestinationInfo, UserPlan, Mtu, Product
)
from app.utils import (
    safe_int, safe_float, points2distance,
    api_ok, api_error, SearchClient,
    get_objectId, wrap_response
)
from app.constants import (
    LOCALITY_SPECIAL_PRODUCTS, MTU_TYPE,
    LOCALITY_APPEND_PRODUCTS, DESTINATION_APPEND_PRODUCTS,
    NEW_LOCALITY_IMAGES,
)
from app.controllers import (
    get_database_version, get_localities_temp,
    get_plan_orders_info_v2, update_or_create_device,
    save_plan_order_mtus,
)


@current_app.route('/vacation/index/', methods=['GET'])
def vacation_index():
    """
    [REST] 自由行首页

    #### 请求参数

        参数名 | 必须 | 类型 | 说明
        ---- | ---- | ---- | ----
        latitude | N | float | 纬度
        longitude | N | float | 经度

        #### 返回结果
        {
            'localities': [
                {
                    'name': '泰国',
                    'name_en': 'Thailand',
                    'distance': '11622km',
                    'temperature': 23,
                    'time': 23:13,
                },
                ...
            ],
    }
    """
    getter = request.args.get
    lat = safe_float(getter('latitude', 0))
    lon = safe_float(getter('longitude', 0))

    localities = Locality.objects.filter(published=True).order_by('position')
    ver = get_database_version(request)

    items = []
    now = datetime.datetime.utcnow()
    temps = get_localities_temp(localities)

    for locality in localities:
        if lon and lat:
            coordinates = locality.location['coordinates']
            pd = points2distance(
                (lon, lat), (
                    coordinates[0],
                    coordinates[1])
            )
            distance = safe_int(pd)
        else:
            distance = None

        hours = 8 - locality.time_zone
        local_time = (now - datetime.timedelta(hours=hours))

        temp = temps.get(locality.id)
        items.append({
            'name': locality.name,
            'name_en': locality.name_en,
            'distance': ('%skm' % distance) if distance else None,
            'temperature': temp,
            'time': local_time.strftime('%H:%M'),
            'cover': locality.cover,
            'database_version': ver[locality.name_en]['database_version'],
            'download_url': ver[locality.name_en]['download_url'],
            'id': str(locality.id),
            'covlocality.iders': NEW_LOCALITY_IMAGES.get(locality.name_en, [])

        })
    return jsonify(localities=items)


@current_app.route('/vacation/locality/<locality_id>/destinations/', methods=['GET'])
@current_app.route('/vacation/destination/<query_type>/', methods=['GET'])
def get_locality_destinations(locality_id=None, query_type=None):
    """
    ### 说明
    通过国家locality_id获取目的地信息

    #### 请求参数
    参数名 | 必选 | 类型及范围 | 说明
    ---- | ---- | ---- | ----
    locality_id | N | string |
    query_type | N | string | 可以为departure-city、 arrival-city

    #### 返回结果 获取出发城市和达到城市列表
    [
        {
            "id": 21,
            "name": "北京"
        }, ...
    ]

    #### 返回结果 获取国家下目的地列表信息
    [
        {
            "recommend_days": 2,
            "name": "龟岛",
            "location": {
                "lng":"",
                "lat":"",
            },
            "tags": [],
            "min_days": 3,
            "max_days": 4,
            "periphery": [
                "苏梅岛",
                "帕岸岛"
            ],
            "destination_id": 17,
            "images": [
                "http://breadtripimages.qiniudn.com/covers_2014_03_01_cc17dd28216aba591281ad5d2feeced8.png?imageView/2/w/960/format/jpg/",
                "http://breadtripimages.qiniudn.com/covers_2014_03_01_159d6e9e09bc37bb2113a7da6898ee46.png?imageView/2/w/960/format/jpg/",
                "http://breadtripimages.qiniudn.com/covers_2014_03_06_eeb6ba6f9608d10177ede175b6d2b4d6.png?imageView/2/w/960/format/jpg",
                "http://breadtripimages.qiniudn.com/covers_2014_03_01_a49749409f7e7646bb0d13c4a3448a6b.png?imageView/2/w/960/format/jpg/"
            ],
            "tags": [
                "文艺",
            ]
        }, ...
    ]
    """
    is_simple_version = 'simple' in request.args

    result = []
    if locality_id:
        contion = Q(
            published=True,
            locality=get_objectId(locality_id),
            is_departured=False
        )
        destination_query = Destination.objects.filter(contion).order_by('position')

        for dest in destination_query:
            location = {}
            if dest.location:
                coordinates = dest.location['coordinates']
                location = dict(
                    lng=coordinates[0],
                    lat=coordinates[1]
                )

            d = dict(
                id=str(dest.id),
                name=dest.name,
                location=location
            )

            max_days = 0
            min_days = 0
            recommend_days = 0
            periphery = []
            images = []
            tags = []

            # 完整版添加推荐天数等信息
            if not is_simple_version:
                d.update({
                    'max_days': max_days,
                    'min_days': min_days,
                    'recommend_days': recommend_days,
                    'periphery': periphery,
                    'images': images,
                    'tags': tags
                })

            info_condition = Q(destination=dest.id)
            destination_info = DestinationInfo.objects.filter(info_condition).first()
            if destination_info:
                max_days = destination_info.max_days
                recommend_days = min_days = destination_info.min_days
                d.update({'recommend_days': recommend_days})

                # 完整版
                if not is_simple_version:
                    # 有图片
                    if destination_info.images:
                        images = json.loads(destination_info.images)
                    periphery = destination_info.periphery.split(u'、')
                    tags = [e.name for e in destination_info.tags]

                    # tags = destination_info.tags.values_list('name', flat=True)
                    d.update({
                        'periphery': periphery,
                        'tags': tags,
                        'images': images,
                        'max_days': max_days,
                        'min_days': min_days
                    })
                    result.append(d)

        return api_ok(data=result)

    # 出发城市和达到城市
    if query_type in ['arrival-city', 'departure-city']:
        result = Destination.objects \
            .filter(is_departured=True) \
            .order_by('position') \
            .only('id', 'name')

    return wrap_response(result)


@current_app.route('/vacation/destination/<destination_id>/options/', methods=['GET'])
@current_app.route('/vacation/destination/option/<option_id>/', methods=['GET'])
def destional_option(option_id=None, destination_id=None):
    """
    目的地玩法列表页和详情页面处handler

    #### 请求参数

    参数名 | 必选 | 类型及范围 | 说明
    ---- | ---- | ---- | ----
    destination_id | No | integer | 获取目的地下全部玩法时提供
    option_id | No | integer | 获取玩法详细信息时提供

    #### 返回结果 玩法详细信息


    #### 返回结果 玩法列表
    [
        {
        "description": "普吉最有名海滩，交通食宿方便，酒吧店铺林立，水上项目繁多，是首登普吉的首选之地。",
        "images": [
            "http://breadtripimages.qiniudn.com/covers_2014_02_28_06577cd02d479fd862cac423d5c4015e.png?imageView/1/w/280/q/75/format/png",
            "http://breadtripimages.qiniudn.com/covers_2014_02_28_a36cea24abd1c9a21693ec2ce3d0a0c7.png?imageView/1/w/280/q/75/format/png",
            "http://breadtripimages.qiniudn.com/covers_2014_02_28_b6ef05f3046890b16fffcb353857ca44.png?imageView/1/w/280/q/75/format/png",
            "http://breadtripimages.qiniudn.com/covers_2014_02_28_8bc3296175b18981681a4fd3bdeecaba.png?imageView/1/w/280/q/75/format/png"
        ],
        "id": 8,
        "name": "初到普吉，感受多彩芭东海滩"
        }, ...
    ]

    """
    condition = Q(is_active=True, published=True, is_booked=False)
    base = DestinationOption.objects.filter(condition)

    app_version = request.breadtrip.version
    if app_version != NoAppVersion():
        if app_version.android:
            app_version = app_version.android
        elif app_version.ios:
            app_version = app_version.ios
        else:
            app_version = '2.0.0'
    else:
        app_version = '2.0.0'

    # 获取目的地下全部玩法
    if destination_id:
        condition = Q(destination=destination_id)
        options_query = base.filter(condition).order_by('position')
        result = []
        for option in options_query:
            images = option.images
            if images:
                images = json.loads(images)
            else:
                images = []

            result.append({
                'id': option.id,
                'name': option.name,
                'images': images,
                'description': option.description
            })
        return wrap_response(result)

    # 获取玩法具体信息
    if option_id:
        obj = base.filter(id=option_id).first()
        d = obj.get_info(with_mtus=True, version=app_version)
        return wrap_response(d)


@current_app.route('/vacation/plan/products/', methods=['POST'])
@validate_form(form_class=PlanBookForm)
def upload_plan():
    """
    [REST] 用户上传计划的数据 MTU版本

    详细见 https://github.com/breadtrip/vacation/wiki/预定数据

    #### 参数

    参数名 | 必须 | 类型 | 说明
    ----- | --- | ---- | ---
    device_id | N | int | device_id
    plan_id | N | int | plan_id 和 device_id 必须有一个存在
    data | Y | text | json数据

    #### data 数据类型
        {
            'items': [
                {
                    'city': {
                        'days': 1,
                        'departure_date': 1430303137,
                        'name': '北京',
                        'destination_id': 21,
                    },
                },
                {
                    'city': {
                        'days': 3,    // 该目的共有几天
                        'departure_date': 0,
                        'name': '清迈',
                        'destination_id': 1,
                    },
                    'days': [
                        {
                            'mtus': {
                                'am': [1, 2, 3 ],  //  上午安排的 mtu_id
                                ...
                            },
                            'day': 1,  //该目的地中的第几天
                        },
                        ...
                    ],
                },
                ...
            ],
        }

    #### 返回数据
        {
            'plan_id': 1,
            'product_count': 12, 可预定产品数量
            'share_id': 'xxxxxxx', 行程分享id
        }
    """
    section_category = {
        'am': 0,
        'pm': 1,
        'night': 2,
        'arrival_half_day': 3,
        'departure_half_day': 4,
    }
    form = g.form
    current_user = g.current_user

    # 获取device_id 和用户信息
    device_id = request.headers.get('HTTP_VACATION_DEVICE_ID')
    if not device_id:
        device_id = form.device_id.data

    user = current_user if current_user.is_authenticated() else None
    if not (device_id or current_user.is_authenticated()) \
            and not form.plan_id.data:
        raise api_error(49999)

    # 判断计划是否存在
    plan = form.plan_id.data
    if plan:
        plan.modify(
            name=form.name.data,
            city_names=form.city_names.data,
            create_date=form.create_date.data,
            app_data=json.dumps(form.data.data)
        )
    else:
        plan = UserPlan(
            device_id=device_id,
            share_id=str(uuid.uuid1()).replace('-', ''),
            name=form.name.data,
            city_names=form.city_names.data,
            create_date=form.create_date.data,
            app_data=json.dumps(form.data.data)
        )

    if form.cover.data:
        url = urlparse(form.cover.data)
        plan.qiniu_cover = url.path

    if not plan.user and user:
        plan.user = user

    plan.save()

    # get destinations
    try:
        destination_ids = set(
            x.get('city', {}).get('destination_id', 0)
            for x in form.data.data.get('items', [])
        )
    except:
        return api_error(49999)
    destinations = Destination.objects.filter(id__in=destination_ids)

    locality_ids = set(
        x.locality_id for x in \
        destinations.filter(is_departured=False)
    )

    special_product_ids = []  # 特殊产品
    for locality_id in locality_ids:
        special_product_ids.extend(
            LOCALITY_SPECIAL_PRODUCTS.get(locality_id, None)
        )

    mtu_ids = []  # 计划中的mtu
    for i, item in enumerate(form.data.data.get('items', [])):
        city = item.get('city', {})
        if not city:
            continue

        destination = destinations.filter(id=city.get('destination_id'))
        if not destination:
            continue

        days = item.get('days', [])
        if not isinstance(days, list):
            return api_error(49999)

        for day in days:
            if not isinstance(day.get('mtus', {}), dict):
                return api_error(49999)

            for k, v in day.get('mtus', {}).items():
                mtu_ids.extend([safe_int(x) for x in v])

    mtus = Mtu.objects.filter(id__in=mtu_ids)

    product_ids = [x.target_id for x in \
                   mtus.filter(target_type=MTU_TYPE.PRODUCT)]

    condition = Q(is_active=True, published=True)
    products = Product.objects.filter(condition)
    product_ids.extend([x.pk for x in products if x not in product_ids])

    # 可附加产品
    for locality_id in locality_ids:
        for k in LOCALITY_APPEND_PRODUCTS.get(locality_id, []):
            if k not in product_ids:
                product_ids.append(k)

    for dest in destinations:
        for k in DESTINATION_APPEND_PRODUCTS.get(dest.pk, []):
            if k not in product_ids:
                product_ids.append(k)

    mtu_condition = Q(
        target_type=MTU_TYPE.PRODUCT,
        target_id__in=product_ids
    )
    mtus = Mtu.objects.filter(mtu_condition)

    save_plan_order_mtus(plan, mtus)
    update_or_create_device(request, is_complete_itinerary=True)
    data = {
        'plan_id': plan.pk,
        'product_count': mtus.count(),
        'share_id': plan.share_id,
    }

    return wrap_response(data)


@current_app.route("/vacation/plan/<plan_id>/orders/", methods=["GET"])
def plan_order():
    """
    用户已预定产品

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    device_id | N | char | 设备id

    #### 返回结果
    {
        'status': 0,
        'message': '',
        'data': {
            'name': 'xxxx一日游',
            'mtu_id': 112,
            'is_booking': false,                // 是否booking
            'destination_id': 2,                // 目的id
            'currency ': 'CNY',
            'template_id': 5,
            'exceed_fee': 200,                  // 超员费用
            'is_can_book': true,
            'category_id': 5,
            'time_summary': 开场时间,
            ...
        },
    }
    """
    getter = request.args.get
    device_id = request.headers.get('HTTP_VACATION_DEVICE_ID')
    if not device_id:
        device_id = getter('device_id')
    if not device_id:
        raise api_error(49999)

    plan_id = getter('plan_id')
    plan = UserPlan.objects.filter(id=plan_id)
    data = get_plan_orders_info_v2(plan)
    result = {
        'status': 0,
        'message': '',
        'data': data,
    }

    return wrap_response(result)


@current_app.route('/vacation/destination/<destination_id>/'
                   'pois/<category_id>/', methods=['GET'])
def mtu_category(destination_id=None, category_id=None):
    getter = request.args.get

    start, count = getter('start', 0), getter('count', 20)
    lng, lat = getter('lng'), getter('lat')

    condition = Q(
        destination=destination_id,
        category_id=category_id
    )
    mtu_query = Mtu.objects.filter(condition).order_by('sort_type')
    items = [mtu.get_info() for mtu in mtu_query]
    if lng and lat and items:
        for item in items:
            item['distance'] = 0
            location = item['location']
            coordinates = location['coordinates']
            if location:
                x, y = safe_float(coordinates[0]), safe_float(coordinates[1])
                distance = points2distance(
                    (safe_float(lng),
                     safe_float(lat)),
                    (x, y)
                )
                item['distance'] = distance
        items.sort(key=lambda x: x['distance'])

    items = items[start:start + count + 1]
    if len(items) <= count:
        next_start = 0
    else:
        next_start = start + count
    result = dict(items=items[:-1], next_start=next_start)
    return wrap_response(result)


@current_app.route('/vacation/poi/search/', methods=['GET'])
@validate_form(VacationPoiSearchForm)
def search_poi():
    """
    poi搜索

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    keyword | Y | Y | 关键字
    destination_id | Y | int | 目的地id
    poi_id | N | int | poi id
    category | N | int | 类型
    start | N | int | 起始值，默认为0。
    count | N | int | 数量，默认为20。

    #### 返回
    poi 详情

    """

    form_data = g.form.__dict__.get('formdata').to_dict()
    getter = form_data.get
    lat, lon = getter('lat'), getter('lon')
    start, count = getter('start', 0), getter('count', 20)
    # c = SearchClient(current_app.config['RUN_ENVIRONMENT'])
    # result = c.search_vacation_mtu(
    #     destination_id=getter('destination_id'),
    #     category=getter('category'),
    #     keyword=getter('keyword'),
    #     lat=lat,
    #     lon=lon,
    #     offset=start,
    #     limit=count + 1
    # )

    destination_id = get_objectId(getter('destination_id'))
    if not destination_id:
        return dict(next_start=0, items=[])

    condition = Q(
        destination=destination_id,
        category=getter('category'),
        keyword=getter('keyword')
    )
    result = Mtu.objects.filter(condition)

    # mtu_ids = result.get("mtu_ids")
    # location_dict = result.get("location_dict")
    mtu_ids = [e.id for e in result]
    location_dict = {e.id: e.location for e in result}

    if int(count) < len(mtu_ids):
        next_start = int(start) + int(count)
    else:
        next_start = None
    mtu_ids = mtu_ids[:count]
    mtu_query = Mtu.objects.filter(pk__in=mtu_ids)
    items = []
    for mtu in mtu_query:
        info = mtu.get_info()
        location = location_dict.get(mtu.pk)
        origin_lat = location['lat']
        origin_lon = location['lon']
        distance = 0

        if lat and lon and location:
            distance = points2distance(
                (safe_float(origin_lon),
                 safe_float(origin_lat)),
                (safe_float(lon), safe_float(lat))
            )
        info['distance'] = distance
        items.append(info)
        items.sort(key=lambda x: mtu_ids.index(x['mtu_id']))

        data = {
            'next_start': next_start,
            'items': items,
        }
        return wrap_response(data)


@current_app.route('/vacation/plan/<plan_id>/share/wechat/', methods=['POST'])
def plan_share(plan_id):
    """
    #### 说明
    产品信息

    #### 请求参数
    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    is_share | Y | Boolean | 是否分享

    #### 返回结果
    {}
    """
    if request.form:
        getter = request.form.get
    else:
        getter = MultiDict(request.get_json(force=True)).get

    plan = UserPlan.objects.filter(id=plan_id).first()
    if plan.is_used_sale:
        return {}

    is_share = getter('is_share', False)
    if not is_share or is_share == "false":
        is_share = False
    else:
        is_share = True

    plan.is_share = is_share
    plan.save()
    return wrap_response({})
